package com.woniu.login.configuration;

import com.woniu.login.filter.JwtAuthFilter;
import com.woniu.login.service.LoginService;
import org.apache.shiro.authc.Authenticator;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.authz.Authorizer;
import org.apache.shiro.authz.ModularRealmAuthorizer;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.util.Arrays;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Bean
    public Authorizer authorizer(){
        return new ModularRealmAuthorizer();
    }
    //  注册Servlet过滤器的类
    @Bean
    public FilterRegistrationBean<Filter> filterRegistrationBean(SecurityManager securityManager, LoginService loginService) throws Exception{
        System.out.println("注册过滤器");
        //  创建过滤器注册工厂
        FilterRegistrationBean<Filter> filterRegistration = new FilterRegistrationBean<Filter>();
        //  注册shiro过滤器
        filterRegistration.setFilter((Filter)shiroFilter(securityManager, loginService).getObject());
        //  设置过滤器由spring管理而不是servlet管理
        filterRegistration.addInitParameter("targetFilterLifecycle", "true");
        //  设置过滤器支持异步处理
        filterRegistration.setAsyncSupported(true);
        //  启用过滤器
        filterRegistration.setEnabled(true);
        //  设置过滤器拦截的请求类型(普通类型和异步类型)
        filterRegistration.setDispatcherTypes(DispatcherType.REQUEST,DispatcherType.ASYNC);

        return filterRegistration;
    }

    //  创建Shiro过滤器
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, LoginService loginService) {
        System.out.println("创建Shiro过滤器");
        // ShiroFilterFactoryBean用于创建Shiro过滤器
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 获取一个包含已注册过滤器的Map。
        Map<String, Filter> filterMap = shiroFilterFactoryBean.getFilters();
        //  创建JWT过滤器
        filterMap.put("authcToken", createAuthFilter(loginService));

        //  创建角色过滤器
//        filterMap.put("anyRole", createRolesFilter());

        //  将一个包含自定义过滤器的Map设置到ShiroFilterFactoryBean实例中
        shiroFilterFactoryBean.setFilters(filterMap);
        // 设置过滤器链
        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());

        return shiroFilterFactoryBean;
    }

    //  创建JWT过滤器,用于处理基于JSON Web Token（JWT）的身份验证。
    protected JwtAuthFilter createAuthFilter(LoginService loginService){
        System.out.println("创建JWT过滤器");
        return new JwtAuthFilter(loginService);
    }


    @Bean
    protected ShiroFilterChainDefinition shiroFilterChainDefinition() {
        System.out.println("创建过滤器链");
        // DefaultShiroFilterChainDefinition用于定义过滤器链
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        //  anon：无需认证（登录）即可访问；authcToken：必须认证（登录）才能访问；user：如果使用rememberMe的功能可以直接访问
        //  roles：该资源必须得到资源权限才能访问；perms：该资源必须得到资源权限才能访问
        //  noSessionCreation：不创建会话
        //  permissive：允许访问
        //  anyRole：只要拥有任意一个角色就可以访问
        chainDefinition.addPathDefinition("/admlogin", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/verifyCode/*", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/mailcode", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/upload", "noSessionCreation,anon");
        chainDefinition.addPathDefinition("/**", "noSessionCreation,authcToken");
//
//        chainDefinition.addPathDefinition("/logout", "noSessionCreation,authcToken[permissive]");
//        chainDefinition.addPathDefinition("/image/**", "anon");
//        chainDefinition.addPathDefinition("/admin/**", "noSessionCreation,authcToken,anyRole[admin,manager]"); //只允许admin或manager角色的用户访问
//        chainDefinition.addPathDefinition("/article/list", "noSessionCreation,authcToken");
//        chainDefinition.addPathDefinition("/article/*", "noSessionCreation,authcToken[permissive]");
//        chainDefinition.addPathDefinition("/**", "noSessionCreation,authcToken");
        return chainDefinition;
    }
    //  负责处理用户的认证（登录）过程
    @Bean
    public Authenticator authenticator(LoginService loginService) {
        System.out.println("创建认证器");
        //  ModularRealmAuthenticator处理多realm认证
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        //  设置认证策略(与JWT（JSON Web Tokens）相关的Realm,与数据库相关的Realm)
        authenticator.setRealms(Arrays.asList(jwtShiroRealm(loginService), dbShiroRealm(loginService)));
        //  设置认证策略（多个Realm时，认证策略为只要第一个成功则认证通过）
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        return authenticator;
    }
    @Bean("dbRealm")
    public Realm dbShiroRealm(LoginService loginService) {
        System.out.println("创建数据库Realm");
        // DbShiroRealm用于处理数据库中的用户认证
        DbShiroRealm myShiroRealm = new DbShiroRealm(loginService);
        return myShiroRealm;
    }

    //  ShiroRealm用于处理JWT（JSON Web Tokens）中的用户认证
    @Bean("jwtRealm")
    public Realm jwtShiroRealm(LoginService loginService) {
        System.out.println("创建JWTRealm");
        // JWTShiroRealm用于处理JWT（JSON Web Tokens）中的用户认证
        JWTShiroRealm myShiroRealm = new JWTShiroRealm(loginService);
        return myShiroRealm;
    }

}
